home *** CD-ROM | disk | FTP | other *** search
/ ETO Development Tools 2 / ETO Development Tools 2.iso / Tools - Objects / MacApp / MacApp CD Release / MacApp 2.0.1 (Many Libraries) / Interfaces / PInterfaces / UMemory.p < prev    next >
Encoding:
Text File  |  1990-10-25  |  18.4 KB  |  415 lines  |  [TEXT/MPS ]

  1. {[a-,body+,h-,o=100,r+,rec+,t=4,u+,#+,j=20/57/1$,n-]}
  2. { UMemory.p }
  3. { Copyright © 1985-1990 by Apple Computer, Inc.  All rights reserved. }
  4.  
  5. {[f-]}
  6. {
  7.     This unit implements MacApp's memory management and segment management
  8.     schemes.
  9.  
  10.     The memory management scheme works by distinguishing between "permanent"
  11.     and "temporary" heap allocation requests.    Permanent requests are
  12.     typically used for data your application allocates:  objects and
  13.     handles.  Temporary requests are used for code segments and Toolbox
  14.     resources and data, such as WDEF's and CDEF's.
  15.  
  16.     Permanent memory objects are considered permanent because they
  17.     are not purged from memory until you explicitly dispose of or free them.
  18.     (Of course, the Macintosh Memory Manager will purge them if they're
  19.     marked purgeable.)    Permanent objects are allocated with NewPermHandle.
  20.     This prevents the MacApp GrowZone from purging temporary objects to
  21.     accommodate a permanent one.  In MacApp, all TObjects and its descendants
  22.     are considered permanent, and are allocated with NewPermHandle.
  23.  
  24.     Temporary memory objects are considered temporary because MacApp's
  25.     GrowZone procedure may purge them from memory to satisfy a memory
  26.     allocation request.  This is true regardless of whether the object is
  27.     marked non-purgeable, although the GrowZone procedure will not purge
  28.     locked objects (such as code segments in use).    Typically, temporary
  29.     objects are marked non-purgeable so that MacApp's GrowZone can control
  30.     when they are purged.
  31.  
  32.     MacApp reserves a specific amount of heap space for temporary objects,
  33.     the idea being that the space reserved is large enough to handle the
  34.     largest number of temporary objects (e.g. code and system resources)
  35.     needed at any given time.    If this amount is sufficiently large, your
  36.     program will never fail loading a segment or system resource.    This
  37.     amount is defined by the internal variable pSzCodeReserve.    You can
  38.     retrieve its value by calling GetReserveSize.    It is initially set by
  39.     the 'seg!' and 'mem!' resources, and can be changed at run-time by
  40.     calling SetReserveSize.  The procedure BuildCodeReserve reserves the
  41.     space by allocating the handle pCodeReserve and setting its size to
  42.     pSzCodeReserve - (the total size of all temporary objects in memory
  43.     [at that time]).
  44.  
  45.     When a temporary object is loaded into memory, the size of pCodeReserve
  46.     is adjusted accordingly. Permanent objects can be loaded into memory
  47.     only so long as there will still be at least pSzCodeReserve bytes
  48.     available for temporary objects.
  49.  
  50.     To identify which objects in the heap are temporary, MacApp maintains
  51.     four lists of handles.    The objects identified by these handles are
  52.     considered temporary and fall under the control of MacApp's GrowZone
  53.     procedure.    The lists are:
  54.  
  55.     gCodeSegs - A list of handles to all CODE resources in the application
  56.     and system resource forks.
  57.  
  58.     gSysMemList - A list handles to RAM-based system resources.
  59.     By default this list includes all PACK, LDEF, MDEF, CDEF and WDEF
  60.     resources in the system and application resource forks. You can add
  61.     other resources, such as fonts, by calling AddHandle.
  62.  
  63.     gApp1MemList, gApp2MemList - Lists of handles to application data or
  64.     resources.    MacApp initializes both lists to NIL.  The difference
  65.     between the two lists is that handles in gApp1MemList are purged
  66.     before those in gApp2MemList.  You may add your own handles to these
  67.     lists by allocating them with NewHandle and calling AddHandle for each
  68.     handle to be added to the list.
  69.  
  70.     The Macintosh Memory Manager calls MacApp's GrowZone procedure only when
  71.     all purgeable objects have been purged from the heap and there is still
  72.     insufficient space to satisfy a memory request.  The GrowZone will
  73.     look through the lists of temporary objects in memory, making one
  74.     purgeable so long as there is still at least pSzCodeReserve bytes
  75.     allocated to temporary memory (the total size of the temporary objects
  76.     in memory and the pCodeReserve handle).  The GrowZone procedure attempts
  77.     to never allow the size of the temporary objects and reserve to fall
  78.     below pSzCodeReserve, thereby guaranteeing that space is always avail-
  79.     able for code segments and system resources (provided pSzCodeReserve is
  80.     large enough to handle your application at its most memory intensive
  81.     state).
  82.  
  83.     The value of pSzCodeReserve is determined at startup-time by adding up
  84.     the size of all the segments named in the 'seg!' resources, and adding
  85.     the first value of each of the 'mem!' resources.  You can derive these
  86.     resources by observing your program and using the MacApp debugger to
  87.     help you determine when your application uses the largest amount of
  88.     code and system resources.    Typically, we've found that this happens
  89.     while printing on the LaserWriter, or during initialization or term-
  90.     ination.
  91.  
  92.     MacApp maintains another reserve, known as the low memory reserve.
  93.     This is a kind of emergency reserve--when all else fails we release
  94.     the pMemReserve handle.  Its size is initially determined by the second
  95.     number of each 'mem!' resource, and can be changed by calling
  96.     SetReserveSize.  You can retrieve its size by calling GetReserveSize.
  97.     Internally, the low-memory reserve is allocated with the pMemReserve
  98.     handle, and its size is stored in pSzMemReserve.
  99.  
  100.     The procedure InitUMemory is responsible for initially setting up the
  101.     temporary and low-memory reserves, setting up the GrowZone procedure,
  102.     initializing handle lists, and patching LoadSeg.  It signals failure
  103.     if the temporary reserve could not be allocated.
  104. }
  105. {[f+]}
  106.  
  107. {$IFC UNDEFINED UsingIncludes}
  108. {$SETC UsingIncludes := FALSE}
  109. {$ENDC}
  110.  
  111. {$IFC NOT UsingIncludes}
  112. UNIT UMemory;
  113.  
  114.     INTERFACE
  115.         {$ENDC}
  116.  
  117.         {$IFC UNDEFINED __UMemory__}
  118.         {$SETC __UMemory__ := FALSE}
  119.         {$ENDC}
  120.  
  121.         {$IFC NOT __UMemory__}
  122.         {$SETC __UMemory__ := TRUE}
  123.  
  124.         { • Auto-Include the requirements for this unit's interface. }
  125.         {$SETC UMemoryIncludes := UsingIncludes}
  126.         {$SETC UsingIncludes := TRUE}
  127.         {$I+}
  128.         {$IFC UNDEFINED UsingTypes} {$I Types.p} {$ENDC}
  129.         {$IFC UNDEFINED UsingMemory} {$I Memory.p} {$ENDC}
  130.         {$IFC UNDEFINED __UPatch__} {$I UPatch.p} {$ENDC}
  131.         {$SETC UsingIncludes := UMemoryIncludes}
  132.  
  133.         CONST
  134.             kGZMaxAlloc         = $7FFFFFFF;
  135.             kCode                = 'CODE';                { Resource type for code }
  136.  
  137.         TYPE
  138.  
  139.             AHandleList         = ARRAY [1..5000] OF Handle; { A list of handles }
  140.             HandleListPtr        = ^AHandleList;         { Preferred }
  141.             HandleListHandle    = ^HandleListPtr;        { Preferred }
  142.             PHandleList         = HandleListPtr;        { Left in for compatibility (2.0) }
  143.             HHandleList         = HandleListHandle;     { Left in for compatibility (2.0) }
  144.  
  145.             ABoolList            = ARRAY [1..5000] OF BOOLEAN; { A list of BOOLEAN }
  146.             BoolListPtr            = ^ABoolList;
  147.             BoolListHandle         = ^BoolListPtr;
  148.             
  149.             ALongList            = ARRAY [1..5000] OF LONGINT; { A list of LONGINT }
  150.             LongListPtr            = ^ALongList;
  151.             LongListHandle        = ^LongListPtr;
  152.  
  153.         VAR
  154.             gMaxLockedRsrc:     Size;                    { The maximum memory consumed by locked
  155.                                                          resources. See CheckRsrcUsage procedure. }
  156.             {$IFC qDebug}
  157.             gMemMgtBreak:        BOOLEAN;                { if TRUE, break into debugger rather than
  158.                                                          just report memory mgt. information }
  159.             gRsrcReport:        BOOLEAN;                { Report resource maximums to the debugger
  160.                                                          window. }
  161.             gSegReport:         BOOLEAN;                { Report segment loadings to the debugger
  162.                                                          window. }
  163.             {$ENDC}
  164.             gSysMemList:        HandleListHandle;        { List of system handles used to compute
  165.                                                          current allocated temporary memory (all
  166.                                                          PACK, LDEF, MDEF, CDEF, WDEF resources).
  167.                                                          See ScanHandles procedure. }
  168.             gApp1MemList,                                { an application defined memlist }
  169.             gApp2MemList:        HandleListHandle;        { These start out NIL. You can create lists
  170.                                                          of handles and place then in either of
  171.                                                          these variables. (One list might be
  172.                                                          permanent handles in your application, and
  173.                                                          the other based on the current situation.)
  174.                                                          The values stored here should be a handle
  175.                                                          to a list of other handles. If you modify
  176.                                                          either of these lists, call CheckReserve.
  177.                                                          It calls BuildAllReserves to recompute the
  178.                                                          code and low space reserve. CheckReserve's
  179.                                                          result indicates whether the full code
  180.                                                          reserve is present. If not, then your
  181.                                                          program may crash because a segment (or
  182.                                                          defproc) can't be loaded. The handles in
  183.                                                          the lists should normally be resources
  184.                                                          that your application might require at any
  185.                                                          given time. All these handles will
  186.                                                          normally be marked non-purgeable. The
  187.                                                          GrowZone proc, however, can purge any of
  188.                                                          these handles that are not locked.}
  189.  
  190.             gCodeRefNum:        INTEGER;                { Reference to where to find code segements
  191.                                                          }
  192.  
  193.             gCodeSegs:            HandleListHandle;        { List of all code segments }
  194.             gIsLoadedSeg:        BoolListHandle;            { Maintains a flag for each segment,
  195.                                                          indicating whether the segment is loaded (in the
  196.                                                          segment loader sense).  Thereby optimizing
  197.                                                          UnloadAllSegments. }
  198.             gIsResidentSeg:        BoolListHandle;            { Maintains a flag for each segment,
  199.                                                          indicating whether the segment is resident
  200.                                                          and hence should not be unloaded (in the
  201.                                                          segment loader sense). }
  202.  
  203.             gUnloadAllSegs:     BOOLEAN;                { UnloadAllSegments doesn't unload segments
  204.                                                         if this flag is false. }
  205.  
  206.             gGZPurgeNotify:     ProcPtr;                { If non-NIL, then this will be called
  207.                                                          before the Grow Zone proc purges a handle.
  208.                                                          The proc will be passed the actual handle.
  209.                                                          }
  210.             { These are meant to be private but are in the interface just in case. }
  211.             pSegSize:            LongListHandle;            { Maintains size of each code resource. }
  212.  
  213.             pCodeReserve:        Handle;                 { Allocates temporary (code) reserve. }
  214.             pMemReserve:        Handle;                 { Allocates low memory reserve. }
  215.             pOKCodeReserve:     BOOLEAN;                { if TRUE then we have an adequate code
  216.                                                          reserve; if FALSE then the application
  217.                                                          could crash if memory is tight }
  218.             pPermAllocation:    BOOLEAN;
  219.             pReserveExists:     BOOLEAN;                { TRUE if the code reserve is known to be
  220.                                                          fully allocated }
  221.             {$IFC qDebug}
  222.             pReserveShortfall:    LONGINT;                { amt. that we are lacking in the code
  223.                                                          reserve }
  224.             {$ENDC}
  225.             pSzCodeReserve:     Size;                    { Attempt to reserve this much memory for
  226.                                                          the temporary (code) reserve. }
  227.             pSzMemReserve:        Size;                    { Attempt to reserve this much memory for
  228.                                                          the low-memory reserve. }
  229.  
  230.             pSegLoadPatch:        TrapPatch;                { patch for LoadSeg }
  231.  
  232.             pOldResFile:        INTEGER;                { The res file reference saved across
  233.                                                          segloads }
  234.             pLoadSegCalledFromOwnApp: BOOLEAN;            { TRUE if calling LoadMacAppSeg from the app
  235.                                                          and not from a _DA_ in our own heap.
  236.                                                          (wheels within wheels for Pete's sake!) }
  237.  
  238.             pMaxSegNum:         INTEGER;                { The maximum segment number }
  239.  
  240.             { I N I T I A L I Z A T I O N }
  241.  
  242.         PROCEDURE InitUMemory;
  243.         { Initializes this unit. Must be called before using this unit. The caller must be in the
  244.         program's main segment. Sets up the gCodeSegs and gSysMemList handle lists, sets the grow
  245.         zone, calls MaxApplZone, sets gApp1MemList and gApp2MemList to NIL, patches LoadSeg and
  246.         allocates the temporary and low-memory reserves. Fails if unable to allocate the temporary
  247.         reserve. }
  248.  
  249.         { S E G M E N T   L O A D I N G }
  250.  
  251.         { DEBUGGING NOTE: You cannot set a MacApp breakpoint at any of these
  252.         routines, because they must not call anything (eg. %_BP) that may
  253.         require a segment load. }
  254.  
  255.         FUNCTION GetSegNumber(aProc: ProcPtr): INTEGER;
  256.         { GetSegNumber returns the number of the segment in which aProc resides. }
  257.  
  258.         FUNCTION GetSegFromPC(ppc: LONGINT): INTEGER;
  259.         { Given a pc pointer, return the segment number or 0 if not found.
  260.         Must be a loaded code segment. }
  261.  
  262.         FUNCTION GetSegSize(segnum: INTEGER): Size;
  263.         { GetSegSize returns the size, in bytes, of the segment whose number is segnum. }
  264.  
  265.         FUNCTION LoadMacAppSegment(segnum: INTEGER): LONGINT;
  266.         { This function patches LoadSeg. It is called from the assembly-language routine
  267.         AMacAppLoadSeg, which is the actual patch setup by PatchTrap. AMacAppLoadSeg saves
  268.         registers and sets up the stack by 1) allocating space for LoadMacAppSegment's result,
  269.         and 2) pushing a copy of LoadSeg's parameter onto the stack for use by LoadMacAppSegment.
  270.         Signals failure if the segment could not be loaded. }
  271.  
  272.         PROCEDURE LoadResidentSegments;
  273.         { Makes resident the segments whose names are included in any 'res!' resources. }
  274.  
  275.         FUNCTION PreloadSegment(segnum: INTEGER): BOOLEAN;
  276.         { PreloadSegment calls PreloadSegmentResource to load a segment in the resource manager
  277.         sense and then calls the segment loader to load it in the segment loader sense. }
  278.  
  279.         FUNCTION PreloadSegmentResource(segnum: INTEGER): BOOLEAN;
  280.         { PreloadSegment is available to programmers who want to lock a segment at the top of the
  281.         heap without having to call a dummy procedure in that segment. It is also useful for
  282.         determining whether a segment can in fact be loaded before you try to execute code in it.
  283.         PreloadSegment returns TRUE if the segment could be loaded, false otherwise. }
  284.  
  285.         PROCEDURE SetResidentSegment(segnum: INTEGER;
  286.                                      makeResident: BOOLEAN);
  287.         { SetResidentSegment can be used to make a segment resident (or no longer resident); resident
  288.         segments will not be unloaded by UnloadAllSegments; if a segment is made resident, it is
  289.         also preloaded.MacApp® automatically marks its resident segment as resident (the one
  290.         containing the procedure CmdFromMenuItem); you probably should do UnloadAllSegments before
  291.         making a segment resident, to ensure that it is locked at the top of the heap. }
  292.  
  293.         PROCEDURE UnloadAllSegments;
  294.         { UnloadAllSegments unloads all segments except the blank segment or the ones marked
  295.         resident. It is called at each iteration of the main event loop to compact memory, as well
  296.         as other places where compacting memory is needed or desirable. }
  297.  
  298.         { H A N D L E L I S T    M A N A G E M E N T }
  299.  
  300.         PROCEDURE AddHandle(h: Handle;
  301.                             toList: HandleListHandle);
  302.         { Adds a handle to the list of handles; does not check if the handle already exists in the
  303.         list. Simply calls Munger to add to the front of the list. }
  304.  
  305.         PROCEDURE AddAllRsrc(rType: ResType;
  306.                              toList: HandleListHandle);
  307.         { Adds all the resources of type rType to the list. Filters out all ROM resources.Calls
  308.         AddHandle. }
  309.  
  310.         PROCEDURE RemHandle(h: Handle;
  311.                             toList: HandleListHandle);
  312.         { Removes the handle from list. }
  313.  
  314.         PROCEDURE ScanHandles(PROCEDURE DoToHandle(h: Handle));
  315.         { Calls DoToHandle for each handle in the lists gCodeSegs, gSysMemList, gApp1MemList and
  316.         gApp2MemList. This procedure assumes that DoToHandle does not compact memory. }
  317.  
  318.         { M E M O R Y M A N A G E M E N T }
  319.  
  320.         PROCEDURE BuildAllReserves;
  321.         { BuildAllReserves creates the code (temporary memory) and low space reserves. These are kept
  322.         for use at a time when an out-of-memory condition has occurred to allow most such
  323.         occurrances to recover smoothly by deallocating the space. }
  324.  
  325.         FUNCTION CheckReserve: BOOLEAN;
  326.         { Checks to see if the code reserve is OK. Calls BuildAllReserves and returns true if the
  327.         full code reserve is present. If this returns false your application may bomb because a
  328.         segment or system resource can't be loaded. }
  329.  
  330.         {$IFC qDebug}
  331.  
  332.         PROCEDURE CheckRsrcUsage;
  333.         { Checks to see if the total size of the currently loaded resources exceeds the maximum
  334.         (gMaxLockedRsrc).If so, the new maximum is set.If gRsrcReport is true, then the new maximum
  335.         is reported in the debugger window.If gMemMgtBreak then program execution is stopped. }
  336.         {$ENDC qDebug}
  337.  
  338.         {$IFC qDebug}
  339.  
  340.         PROCEDURE DoChangeReserve(alter: BOOLEAN;
  341.                                   VAR codeReserve, codeShort, lowSpaceReserve: Size;
  342.                                   VAR gotCode, gotLowSpace: BOOLEAN);
  343.         { Called by the MacApp® debugger to change the reserve allocation. Not normally called by an
  344.         application. }
  345.         {$ENDC qDebug}
  346.  
  347.         PROCEDURE FailNoReserve;
  348.         { IF NOT CheckReserve THEN Failure(memFullErr, 0). }
  349.  
  350.         PROCEDURE FailSpaceIsLow;
  351.         { IF MemSpaceIsLow THEN Failure(memFullErr, 0). }
  352.  
  353.         PROCEDURE GetReserveSize(VAR szCodeReserve, szMemReserve: Size);
  354.         { Returns the amount of memory that is to be reserved for the code and memory reserve. This
  355.         is not a true indication of whether this amount of memory has in fact been reserved. Call
  356.         CheckReserve to find out if the code reserve could be allocated, and call MemSpaceIsLow to
  357.         find out if the low-memory reserve could be allocated. }
  358.  
  359.         FUNCTION MemSpaceIsLow: BOOLEAN;
  360.         { Returns TRUE if the low space reserve is missing. }
  361.  
  362.         FUNCTION NewPermPtr(logicalSize: Size): Ptr;
  363.         { Allocates a permanent Pointer; you should call this instead of NewPointer if allocating
  364.         some permanent memory. }
  365.  
  366.         FUNCTION NewPermHandle(logicalSize: Size): Handle;
  367.         { Allocates a permanent handle; you should call this instead of NewHandle if allocating some
  368.         permanent memory. }
  369.  
  370.         FUNCTION PermAllocation(permanent: BOOLEAN): BOOLEAN;
  371.         { PermAllocation controls whether subsequent memory allocations are considered permanent or
  372.         temporary.Pass TRUE to setup things for a permanent allocation.Returns the previous state
  373.         of the permanent flag. }
  374.  
  375.         PROCEDURE SetPermHandleSize(h: Handle;
  376.                                     newSize: Size);
  377.         { Use this call to size permanent handles. It sets/resets the permanent flag correctly and
  378.         does a FailMemError. }
  379.  
  380.         PROCEDURE SetPermPtrSize(p: Ptr;
  381.                                  newSize: Size);
  382.         { Use this call to size permanent pointers. It sets/resets the permanent flag correctly and
  383.         does a FailMemError. }
  384.  
  385.         PROCEDURE SetReserveSize(forCode, forOther: Size);
  386.         { Call this to set the size of the memory reserved for code (temporary) and permanent (low
  387.         memory) requests. }
  388.  
  389.         FUNCTION TotalTempSize(justLocked: BOOLEAN;
  390.                                VAR canPurge: Handle): Size;
  391.         { TotalTempSize returns the total number of bytes of the temporary handles currently in RAM
  392.         (or only locked/in use handles if justLocked is TRUE).  CanPurge is set to an unlocked
  393.         handle that can be purged if desired.  Uses ScanHandles. }
  394.  
  395.         {$IFC qDebug}
  396.  
  397.         PROCEDURE WriteReserves;
  398.         { WRITELN's the temporary reserve and low-memory reserves in the debug window. }
  399.         {$ENDC}
  400.  
  401.         { U T I L I T I E S }
  402.  
  403.         FUNCTION AddSegSizes(segRsrc: Handle): Size;
  404.         { Returns the total size of the code segments whose names are in the string list segRrsc. }
  405.  
  406.         PROCEDURE SetStackSpace(numBytes: Size);
  407.         { Set the stack space to at least numBytes. }
  408.         {$ENDC}
  409.  
  410.         PROCEDURE WithCodeResFileDo(PROCEDURE DoWithResFile);
  411.         { Ensure that the resource call is done against gCodeRefNum }
  412.         {$IFC NOT UsingIncludes}
  413. END.
  414. {$ENDC}
  415.